// Tencent is pleased to support the open source community by making Mars available.
// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.

// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://opensource.org/licenses/MIT

// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.

//
//  dnschecker.cc
//  netchecker
//
//  Author: renlibin caoshaokun on 24/6/14.
//  Copyright (c) 2014 Tencent. All rights reserved.
//

#include "dnschecker.h"

#include "mars/comm/singleton.h"
#include "mars/comm/time_utils.h"
#include "mars/comm/xlogger/xlogger.h"
#include "mars/sdt/constants.h"
#include "sdt/src/checkimpl/dnsquery.h"

using namespace mars::sdt;

DnsChecker::DnsChecker() {
    xverbose_function();
}

DnsChecker::~DnsChecker() {
    xverbose_function();
}

int DnsChecker::StartDoCheck(CheckRequestProfile& _check_request) {
    xinfo_function();
    return BaseChecker::StartDoCheck(_check_request);
}

void DnsChecker::__DoCheck(CheckRequestProfile& _check_request) {
    xinfo_function();

    // longlink host dns
    for (CheckIPPorts_Iterator iter = _check_request.longlink_items.begin();
         iter != _check_request.longlink_items.end();
         ++iter) {
        if (is_canceled_) {
            xinfo2(TSF "HttpChecker is canceled.");
            return;
        }

        CheckResultProfile profile;
        profile.domain_name = iter->first;
        profile.netcheck_type = kDnsCheck;
        profile.network_type = comm::getNetInfo();

        struct socket_ipinfo_t ipinfo;
        int timeout =
            (_check_request.total_timeout == UNUSE_TIMEOUT ? DEFAULT_DNS_TIMEOUT : _check_request.total_timeout);
        uint64_t start_time = gettickcount();
        int ret = socket_gethostbyname(profile.domain_name.c_str(), &ipinfo, timeout, NULL);
        uint64_t cost_time = gettickcount() - start_time;

        profile.error_code = ret;
        profile.rtt = cost_time;

        if (0 == ret) {
            xinfo2(TSF "%0, check dns, host: %1, ret: %2", NET_CHECK_TAG, profile.domain_name, CHECK_SUC);
            if (ipinfo.size >= 2) {
                profile.ip1 = inet_ntoa(ipinfo.ip[0]);
                profile.ip2 = inet_ntoa(ipinfo.ip[1]);
            } else if (1 == ipinfo.size) {
                profile.ip1 = inet_ntoa(ipinfo.ip[0]);
            } else {
                xerror2(TSF "ret = 0, but ipinfo.size = %0", ipinfo.size);
            }
        } else {
            xinfo2(TSF "%0, check dns, host: %1, ret: %2", NET_CHECK_TAG, profile.domain_name, CHECK_FAIL);
        }

        _check_request.checkresult_profiles.push_back(profile);
        _check_request.check_status = (ret >= 0 ? kCheckContinue : kCheckFinish);

        if (_check_request.total_timeout != UNUSE_TIMEOUT) {
            _check_request.total_timeout -= cost_time;
            if (_check_request.total_timeout <= 0) {
                xinfo2(TSF "dns check, host: %0, timeout.", profile.domain_name);
                break;
            }
        }
    }

    // shortlink host dns
    for (CheckIPPorts_Iterator iter = _check_request.shortlink_items.begin();
         iter != _check_request.shortlink_items.end();
         ++iter) {
        if (is_canceled_) {
            xinfo2(TSF "HttpChecker is canceled.");
            return;
        }

        CheckResultProfile profile;
        profile.domain_name = iter->first;
        profile.netcheck_type = kDnsCheck;
        profile.network_type = comm::getNetInfo();

        struct socket_ipinfo_t ipinfo;
        int timeout =
            (_check_request.total_timeout == UNUSE_TIMEOUT ? DEFAULT_DNS_TIMEOUT : _check_request.total_timeout);
        uint64_t start_time = gettickcount();
        int ret = socket_gethostbyname(profile.domain_name.c_str(), &ipinfo, timeout, NULL);
        uint64_t cost_time = gettickcount() - start_time;

        profile.error_code = ret;
        profile.rtt = cost_time;

        if (0 == ret) {
            xinfo2(TSF "%0, check dns, host: %1, ret: %2", NET_CHECK_TAG, profile.domain_name, CHECK_SUC);
            if (ipinfo.size >= 2) {
                profile.ip1 = inet_ntoa(ipinfo.ip[0]);
                profile.ip2 = inet_ntoa(ipinfo.ip[1]);
            } else if (1 == ipinfo.size) {
                profile.ip1 = inet_ntoa(ipinfo.ip[0]);
            } else {
                xerror2(TSF "ret = 0, but ipinfo.size = %0", ipinfo.size);
            }
        } else {
            xinfo2(TSF "%0, check dns, host: %1, ret: %2", NET_CHECK_TAG, profile.domain_name, CHECK_FAIL);
        }

        _check_request.checkresult_profiles.push_back(profile);
        _check_request.check_status = (ret >= 0 ? kCheckContinue : kCheckFinish);

        if (_check_request.total_timeout != UNUSE_TIMEOUT) {
            _check_request.total_timeout -= cost_time;
            if (_check_request.total_timeout <= 0) {
                xinfo2(TSF "dns check, host: %0, timeout.", profile.domain_name);
                break;
            }
        }
    }
}
